#pragma once

#include <compl.h>
typedef void mmeta_t;

/* 加入meta信息后返回新指针和 */

/* 申请 */
/* 模块metatype, metasize(宏输入, 输入0则是不定长metasize, 传统都是定长meta ) (ptr) -> (mmeta_t *) 申请meta信息空间 */
/* 设置meta内容 (mmeta_t *, ptr, size, ...) -> (ptr, size) 要填入meta的内容,返回一个可用size和指针 */
/* 释放时 */
/* (fptr) -> (meta_t *) get meta指针,然后根据自己编码的信息解码获得大小，或者clear meta */
/* 如果按对齐方式区分, free时可以不着急获得size，等到用的时候在获得。 */

/* 用于区分 malloc返回和free时的指针 */
typedef void fvoid;

/* 这个可以用宏实现不定长 */

STA_OUFUN(mmeta)
void (* const mmeta_init) ();
void (* const mmeta_tinit) ();
/* meta信息占用内存块大小 */
size_t (* const mmeta_ocupysize) (size_t msize); /* 获得之后是拷贝还是赋值随意, 传入内存大小是为了检查是否满足与接口对称性 */
mmeta_t * (* const mmeta_by_ptr) (void *ptr, size_t size, size_t msize, fvoid **pfptr); /* 写入meta信息后通过该接口转换,并得到真实大小 */
mmeta_t * (* const mmeta_by_fptr) (fvoid *fptr, size_t size, void **pptr); /* mmeta不为空时, fptr写入 pptr */
END_OUFUN(mmeta)

// #define MMETA_CEFF(name)	mmeta_init_##name, mmeta_tinit_##name, mmeta_ocupysize_##name, mmeta_by_ptr_##name, mmeta_by_fptr_##name
// #define MMETA_CEFF_ALL	  	MMETA_CEFF()

/* init是给外部信息meta初始化用的 */
#define DECL_MMETA(name, metatype)		  \
SAI void mmeta_init_##name();\
SAI void mmeta_tinit_##name();\
SAI size_t mmeta_ocupysize_##name (size_t msize);\
SAI mmeta_t *mmeta_by_ptr_##name (void *ptr, size_t size, size_t msize, fvoid **pfptr);\
SAI mmeta_t *mmeta_by_fptr_##name (fvoid *fptr, size_t size, void **pptr);\
NEW_OUFUN(mmeta, name, mmeta_init_##name, mmeta_tinit_##name, mmeta_ocupysize_##name, mmeta_by_ptr_##name, mmeta_by_fptr_##name)
/* 头部信息 尾部信息 和外部信息 */
/* 从头部分配meta信息, 支持不定长度 */
/* 注意使用这个内存就不对齐了 */
#define DEF_MMETA_HD(name, metatype, metasize)\
DECL_MMETA(name, metatype)\
SAI void mmeta_init_##name (){};\
SAI void mmeta_tinit_##name(){};\
SAI size_t	 mmeta_ocupysize_##name (size_t msize){ \
	if(metasize == 0) return msize + sizeof(metatype **); return metasize; }\
SAI mmeta_t   *mmeta_by_ptr_##name (void *ptr, size_t size, size_t msize, fvoid **pfptr){\
	PARAM_USED(size);\
	if (metasize == 0) {\
		*(metatype   **)(ptr + msize) = (metatype *)ptr;\
		*pfptr = (fvoid *)(ptr + msize + sizeof(metatype **));  /* 不定长度, 余下可用长度 */\
	}\
	else *pfptr = (fvoid *)(ptr + metasize); /* 定长 */\
	return (metatype *)ptr; /* meta指针在头部 */}\
SAI mmeta_t   *mmeta_by_fptr_##name (fvoid *fptr, size_t size, void **pptr){\
	PARAM_USED(size);\
	metatype *ret;\
	if (metasize == 0){\
		/* 不定长度*/\
		metatype   *pret = *(metatype   **)(fptr - sizeof(metatype **));\
		ret = pret;		 \
		*pptr = (void *)ret; \
	}else{\
		ret = (fvoid *)(fptr - metasize);\
		*pptr = (void *)ret;\
	}\
	return (metatype *)ret;}
	
/* 从尾部分配meta信息, 头部必须存一个mmeta指针否则索引不到尾部数据块 */
#define DEF_MMETA_TL(name, metatype, metasize)\
DECL_MMETA(name, metatype)\
SAI void mmeta_init_##name (){};\
SAI void mmeta_tinit_##name(){};\
SAI size_t mmeta_ocupysize_##name (size_t msize){ \
	if(metasize == 0) return msize + sizeof(metatype **);\
	return metasize + sizeof(metatype **); }\
SAI mmeta_t *mmeta_by_ptr_##name (void *ptr, size_t size, size_t msize, fvoid **pfptr){\
	metatype **mptr = (metatype **)ptr;\
	*pfptr = (fvoid *)(ptr + sizeof(metatype **));\
	if(metasize == 0) {\
		*mptr = (metatype *)(ptr + size - msize);\
		return (metatype *)(ptr + size - msize);\
	}\
	*mptr = (metatype *)(ptr + size - metasize);\
	return (metatype *)(ptr + size - metasize); }\
SAI mmeta_t *mmeta_by_fptr_##name (fvoid *fptr, size_t size, void **pptr){\
	PARAM_USED(size);\
	metatype **ret;\
	ret = (metatype **)(fptr - sizeof(metatype **));\
	*pptr = (void *)ret;\
	return *ret;}

/* 纯尾部，大小由其他接口获得 */
#define DEF_MMETA_TL_PURE(name, metatype, metasize)\
DECL_MMETA(name, metatype)\
SAI void mmeta_init_##name (){};\
SAI void mmeta_tinit_##name(){};\
SAI size_t mmeta_ocupysize_##name (size_t msize){ \
	PARAM_USED(msize);\
	return metasize; }\
SAI mmeta_t *mmeta_by_ptr_##name (void *ptr, size_t size, size_t msize, fvoid **pfptr){\
	PARAM_USED(msize);\
	*pfptr = (fvoid *)(ptr);\
	return (metatype *)(ptr + size - metasize); }\
SAI mmeta_t *mmeta_by_fptr_##name (fvoid *fptr, size_t size, void **pptr){\
	metatype *ret = (metatype *)(fptr + size - metasize);\
	*pptr = (void *)fptr;\
	return ret;}
